package edu.eam.dao;

import edu.eam.modelo.Categoria;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;

public class DAOCategoria {
    
    
    private Connection conex;
    
    public DAOCategoria() {
    }
        
    /**
     * Constructor de la case, recibiendo la conexion a la base de datos.
     * @param Connection conex 
     */
    public DAOCategoria(Connection conex) {
            this.conex = conex;
    }
    
    /**
     * Metodo que nos permite ingresar una categoria o subcategoria en la BD
     *
     * @param Categoria categoria
     * @throws SQLException
     */
    public void crearCategoria(Categoria categoria) throws SQLException, Exception {
        //Si ya existe el nombre en la base de datos, mostramos un error.
        if (buscarCategoriaPorNombre(categoria.getNombre()) != null) {
            throw new Exception("Este nombre ya existe.");
        }
        //Este metodo no deja agregar mas de 4 niveles de categorais
        cuatroNivelesComoMaximo(categoria);        
        // Consulta para insertar una categoria
        String consulta = "INSERT INTO categoria_subcategoria (nombre, padre) "
                + "VALUES (?, ?)";
        PreparedStatement pstm = null;
        try {
            //enviamos la consulta al PreparedStatement
            pstm = conex.prepareStatement(consulta);
            //Damos los valores a la consulta.
            pstm.setString(1, categoria.getNombre());
            pstm.setInt(2, categoria.getPadre());
            //Ejecutamos la consulta.
            pstm.executeUpdate();
        } catch (SQLException ex) {
            //Mostramos error al crear la consulta
            JOptionPane.showMessageDialog(null, "Error al crear la categoria", 
                    "Error", JOptionPane.ERROR_MESSAGE);
        } finally {
            //cerramos la conexion.
            if (pstm != null) {
                pstm.close();
            }
        } 
    }
    
   /**
    * Metodo que nos permite buscar una categoria por el codigo.
    * @param int idCategoria
    * @return Categoria categoria con el id,
    * @throws SQLException 
    */
    public Categoria buscarCategoriaPorID(int idCategoria) throws SQLException {
        //Consulta que nos permite buscar una categoria por el nombre
        String consulta = "SELECT nombre, padre FROM categoria_subcategoria "
                + "WHERE id = ?";
        //Declaramos el PreparedStatement y el ResultSet para ejecutar y 
        //obtener los resultados, respectivamente
        PreparedStatement pstm = null;        
        ResultSet res = null;
        //Declaramos un objeto Categoria para almacenar los datos y retornar 
        //el objeto.
        Categoria categoria = null;
        try {
            //enviamos la consulta.
            pstm = conex.prepareStatement(consulta);
            // Colocamos los parametros.
            pstm.setInt(1, idCategoria);
            //Ejecutamos la consulta.
            res = pstm.executeQuery();
            //Si obtenemos algun resultado de la consulta, obtendremos los datos
            //de ella.
            if (res.next()) {
                String nombre = res.getString(1);
                int padre = res.getInt(2);
                //Istanciamos la categoria con los datos de la consulta.
                categoria = new Categoria(idCategoria, nombre, padre);
            }

        }catch (SQLException ex) {
            //Mostramos error al buscar la consulta
            JOptionPane.showMessageDialog(null, ex.getMessage(), 
                    "Error", JOptionPane.ERROR_MESSAGE);
        } finally {
            //Cerramos la conexion
            if (pstm != null) {
                pstm.close();
            }
            //Cerramos el Resultset.
            if (res != null) {
                res.close();
            }
        }
        //Retornamos la categoria buscada.
        return categoria;
    }
    
    /**
    * Metodo que nos permite buscar una categoria por el codigo.
    * @param int idCategoria
    * @return Categoria categoria con el id,
    * @throws SQLException 
    */
    public ArrayList<Categoria> todasLasCategoriasParaArbol() throws SQLException {
        //Consulta que nos permite buscar una categoria por el nombre
        String consulta = "SELECT id, nombre, padre FROM categoria_subcategoria";
        //Declaramos el PreparedStatement y el ResultSet para ejecutar y 
        //obtener los resultados, respectivamente
        PreparedStatement pstm = null;        
        ResultSet res = null;
        ArrayList<Categoria> categorias = new ArrayList<Categoria>();
        try {
            //enviamos la consulta.
            pstm = conex.prepareStatement(consulta);
            //Ejecutamos la consulta.
            res = pstm.executeQuery();
            //Si obtenemos algun resultado de la consulta, obtendremos los datos
            //de ella.
            
            while (res.next()) {
                int id = res.getInt(1);
                String nombre = res.getString(2);
                int padre = res.getInt(3);
                //Istanciamos la categoria con los datos de la consulta.
                categorias.add(new Categoria(id, nombre, padre));
            }

        }catch (SQLException ex) {
            //Mostramos error al buscar la consulta
            JOptionPane.showMessageDialog(null, ex.getMessage(), 
                    "Error", JOptionPane.ERROR_MESSAGE);
        } finally {
            //Cerramos la conexion
            if (pstm != null) {
                pstm.close();
            }
            //Cerramos el Resultset.
            if (res != null) {
                res.close();
            }
        }
        if (categorias.size() == 0) {
            try {
                crearCategoria(new Categoria(0, "Categorias", 0));
                todasLasCategoriasParaArbol();
            } catch (Exception ex) {
                Logger.getLogger(DAOCategoria.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
        //Retornamos la categoria buscada.
        return categorias;
        
    }
    
    /**
    * Metodo que nos permite buscar una categoria por el nombre.
    * @param String nombreCategoria
    * @return Categoria categoria con el id,
    * @throws SQLException 
    */
    public Categoria buscarCategoriaPorNombre(String nombreCategoria) throws SQLException {
        //Consulta que nos permite buscar una categoria por el nombre
        String consulta = "SELECT id, padre FROM categoria_subcategoria "
                + "WHERE nombre = ?";
        //Declaramos el PreparedStatement y el ResultSet para ejecutar y 
        //obtener los resultados, respectivamente
        PreparedStatement pstm = null;        
        ResultSet res = null;
        //Declaramos un objeto Categoria para almacenar los datos y retornar 
        //el objeto.
        Categoria categoria = null;
        try {
            //enviamos la consulta.
            pstm = conex.prepareStatement(consulta);
            // Colocamos los parametros.
            pstm.setString(1, nombreCategoria);
            //Ejecutamos la consulta.
            res = pstm.executeQuery();
            //Si obtenemos algun resultado de la consulta, obtendremos los datos
            //de ella.
            if (res.next()) {
                int codigo = res.getInt(1);
                int padre = res.getInt(2);
                //Istanciamos la categoria con los datos de la consulta.
                categoria = new Categoria(codigo, nombreCategoria, padre);
            }

        }catch (SQLException ex) {
            //Mostramos error al buscar la consulta
            JOptionPane.showMessageDialog(null, ex.getMessage(), 
                    "Error", JOptionPane.ERROR_MESSAGE);
        } finally {
            //Cerramos la conexion
            if (pstm != null) {
                pstm.close();
            }
            //Cerramos el Resultset.
            if (res != null) {
                res.close();
            }
        }
        //Retornamos la categoria buscada.
        return categoria;
    }

    /**
     * Metodo que permte tener un maximo de 4 niveles en las categorias
     * @param categoria
     * @throws SQLException
     * @throws Exception 
     */
    private void cuatroNivelesComoMaximo(Categoria categoria) throws SQLException, Exception {
        //Cantidad de niveles
        int conteo = 0;
        Categoria tempo = categoria;
        do {
            //Buscamos la categoria padre de la categoria actual
             tempo = buscarCategoriaPorID(tempo.getPadre());   
             conteo ++;
        }while (tempo.getCodigo() != 0);
        //Si el conteo de niveles es igual o superior a 4 mostramos la excepcion.
        if (conteo >= 4) {
            throw new Exception("No se puede insertar la categoria porque "
                    + "solo se puede tener un maximo de 4 niveles.");
        }
        
    }
    

}
